package javassist;


import java.io.IOException;

public class JavassistDemo {
    public static Class genClass() throws NotFoundException, IOException, CannotCompileException {
        //创建一个字节码池，用来存放生成的Class
        ClassPool pool = ClassPool.getDefault();
        // 创建一个User类
        CtClass clz = pool.makeClass("cn.example.User");

        // 创建一个String变量name
        CtField nameField = new CtField(pool.get("java.lang.String"), "name", clz);
        // 设置name成员变量为私有属性,不设默认Public
        nameField.setModifiers(Modifier.PRIVATE);
        // 将name成员变量添加到Person类中
        clz.addField(nameField);

        // 创建一个Integer变量name
        CtField ageField = new CtField(pool.get("java.lang.Integer"), "age", clz);
        // 设置name成员变量为私有属性,不设默认Public
        ageField.setModifiers(Modifier.PRIVATE);
        // 将name成员变量添加到Person类中
        clz.addField(ageField);

        // 添加一个无参数构造方法
        CtConstructor defaultConstructor = new CtConstructor(new CtClass[]{}, clz);
        // 设置方法体内容
        defaultConstructor.setBody("{name = \"\";}");
        clz.addConstructor(defaultConstructor);

        // 添加一个有参数的构造方法
        CtConstructor paramsConstructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, clz);
        // 设置方法体内容 $0表示this，$1,$2...表示方法参数
        paramsConstructor.setBody("{$0.name = $1;}");
        clz.addConstructor(paramsConstructor);

        // 添加一个sayHello 无参的方法
        CtMethod sayHello = new CtMethod(CtClass.voidType, "sayHello", new CtClass[]{}, clz);
        //设置方法为PRIVATE，默认为PUBLIC
        sayHello.setModifiers(Modifier.PRIVATE);
        //设置方法体内容
        sayHello.setBody("System.out.println(\"hello, this is \" + $0.name);");
        clz.addMethod(sayHello);

        // 添加一个sayHello 有参的方法
        CtMethod sayHelloWithParam = new CtMethod(CtClass.voidType, "sayHello", new CtClass[]{pool.get("java.lang.String")}, clz);
        //设置方法为PRIVATE，默认为PUBLIC
        sayHelloWithParam.setModifiers(Modifier.PRIVATE + Modifier.STATIC);
        //设置方法体内容
        sayHelloWithParam.setBody("System.out.println(\"hello, this is \" + $1);");
        clz.addMethod(sayHelloWithParam);

        ////////////////////添加接口////////////////////////////////
//        // 创建IUser接口
//        CtClass iUser = pool.makeInterface("cn.example.IUser");
//        // 接口添加一个sayHello1有参方法
//        iUser.addMethod(new CtMethod(CtClass.voidType,
//                "sayHello1", new CtClass[]{}, iUser));
//        clz.addInterface(iUser);

//        iUser.addMethod(CtNewMethod.abstractMethod(CtClass.voidType, "sayHello1",
//                new CtClass[]{}, null, iUser));
//        CtMethod sayHello1 = new CtMethod(CtClass.voidType, "sayHello1", new CtClass[]{}, clz);
        //设置方法体内容
//        sayHello1.setBody("System.out.println(\"hello, this is \");");
//        clz.addMethod(sayHello1);
//        clz.setInterfaces(new CtClass[]{iUser});

//        clz.addMethod(CtNewMethod.wrapped(CtClass.voidType,
//                "sayHello1",
//                new CtClass[]{pool.get("java.lang.String")},
//                null, null, null, clz));
//        iUser.writeFile();
        ////////////////////添加接口////////////////////////////////

        ////////////////////添加一个main方法/////////////////
        //添加一个main方法
        CtMethod ctMethod = new CtMethod(CtClass.voidType, "main", new CtClass[]{pool.get(String[].class.getName())}, clz);
        //将main方法声明为public static类型
        ctMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
        //设置方法体
        ctMethod.setBody("{" +
                "" +
                "}");
        clz.addMethod(ctMethod);
        ////////////////////添加一个main方法/////////////////
        CtClass.debugDump = "./dump";
        //写入本地
        clz.writeFile();
        return clz.toClass();
    }

    public static void loadClass() throws Exception {
        //创建一个字节码池，用来存放加载进来的Class
        ClassPool pool = ClassPool.getDefault();
        //添加Class路径，不能包括包名 appendClassPath跟insertClassPath效果一样
        pool.appendClassPath("D:\\20210426\\code\\otherCode\\GradlePluginDemo");
//        pool.insertClassPath("D:\\20210426\\code\\otherCode\\GradlePluginDemo");
        // 获取User.Class，不能加.class
        CtClass clz = pool.get("cn.example.User");
        System.out.println("clz:"+clz);
        clz.defrost();
        for (CtField field : clz.getDeclaredFields()) {
            System.out.println("field name:"+field.getName());
            if (field.getName().equals("name")){
                clz.removeField(field);
            }
        }

        for (CtConstructor constructor : clz.getDeclaredConstructors()) {
            System.out.println("constructor name:"+constructor.getName());
            if (constructor.getName().equals("User")){
                clz.removeConstructor(constructor);
            }
        }

        for (CtMethod method : clz.getDeclaredMethods()) {
            System.out.println("method name:"+method.getName());
            if (method.getName().equals("sayHello")){
                clz.removeMethod(method);
            }
        }

        clz.writeFile();
        clz.detach();
    }

    public static void main(String[] args) throws Exception {
        //测试
        Class clazz = genClass();
//        Object obj = clazz.newInstance();
//        Method mainMethod = clazz.getMethod("main", new Class[]{String[].class});
//        mainMethod.invoke(obj, new String[1]);


//        loadClass();
    }

}
